using System;
using MilkShake;
using UnityEngine;
using UnityEngine.Events;

public class Weapon : MonoBehaviour
{
	[Serializable]
	public struct ChargeConfig
	{
		public float duration;

		public float damage;

		public float penetration;

		public float stoppingPower;

		public float recoil;

		public float shakePower;

		public AudioClip fireAudio;

		public UnityEvent callback;

		[HideInInspector]
		public bool hasApplied;
	}

	[HideInInspector]
	public Player player;

	public Animator animator;

	public GameObject rightHandHandler;

	public GameObject leftHandHandler;

	public GameObject magazineHandler;

	public BulletFire bulletFire;

	public LineRenderer bulletLine;

	public BulletShell bulletShell;

	public GameObject magazineWell;

	public GameObject magazinePos;

	public AudioSource audioSource;

	public AudioClip fireAudio;

	public AudioClip lastAmmoAudio;

	public BulletShell bulletClip;

	public ShakePreset shake;

	public bool autoCocking;

	public bool isBulletStay;

	public bool rightHandReload;

	public bool noReloadPosition;

	public float damage = 33f;

	public float recoil = 2f;

	public float shakePower = 1f;

	public int capacity = 30;

	public bool automatic;

	public float reloadTime = 6.1f;

	public float rpm = 666f;

	[Tooltip("penetration - Hit character health > 0 then go to hit next character")]
	public float penetration = 100f;

	public float stoppingPower = 50f;

	[Tooltip("For shotgun, each burst create a raycast, 0 only 1 raycast.")]
	public int burstCount;

	public AudioClip warmupAudio;

	public AudioClip fireLoopAudio;

	public AudioClip sleepAudio;

	public GameObject projectileObject;

	public float projectileForce;

	public ParticleSystem launcherSmoke;

	public ChargeConfig[] chargeConfigs;

	private float _chargeShakePower;

	public UnityEvent OnStopFire;

	[Header("Runtime")]
	private float fireSince;

	private float lastFireAt;

	private float lastRealodAt;

	public bool onFire;

	public int ammo;

	public Magazine magazine;

	private Magazine dropMagazine;

	public bool cocked;

	public bool onReload;

	public bool newMagazinePickedUp;

	public bool newMagazineReady;

	public bool newMagazineChanged;

	public Vector2 offset;

	public bool isTools;

	private void Awake()
	{
		if (!isTools)
		{
			ammo = capacity;
			cocked = true;
			newMagazineChanged = true;
			magazine = magazinePos.transform.GetChild(0).gameObject.GetComponent<Magazine>();
			offset = bulletFire.transform.localPosition + base.transform.Find("Body").localPosition;
			if ((bool)bulletFire.ps)
			{
				bulletFire.StopPs();
			}
		}
	}

	private void Start()
	{
		if (!isTools && (bool)player)
		{
			animator.SetFloat("speed", 0.5f + player.speed / 4f);
		}
	}

	private void Update()
	{
		if (isTools || !player)
		{
			return;
		}
		if (onReload)
		{
			float num = 1f + player.speed;
			GameObject gameObject = (rightHandReload ? rightHandHandler : leftHandHandler);
			if (!newMagazinePickedUp && Time.time - lastRealodAt > 4f)
			{
				TakeMagazion(gameObject);
				MagazineChanged();
				Cocked();
				Reload();
			}
			if (noReloadPosition)
			{
				TakeMagazion(gameObject);
				animator.enabled = true;
			}
			else if (!cocked && !newMagazinePickedUp)
			{
				if (Vector2.Distance(gameObject.transform.position, magazine.transform.position) <= 0.2f)
				{
					num /= 8f;
				}
				gameObject.transform.position = Vector2.MoveTowards(gameObject.transform.position, magazine.transform.position, num * Time.deltaTime);
				if (Vector2.Distance(gameObject.transform.position, magazine.transform.position) <= 0.05f)
				{
					TakeMagazion(gameObject);
				}
			}
			else if (!cocked && !newMagazineReady)
			{
				gameObject.transform.position = Vector2.MoveTowards(gameObject.transform.position, magazineHandler.transform.position, num * Time.deltaTime);
				if (Vector2.Distance(gameObject.transform.position, magazineHandler.transform.position) <= 0.05f)
				{
					newMagazineReady = true;
				}
			}
			if (newMagazineReady)
			{
				animator.enabled = true;
			}
		}
		else
		{
			Fire();
		}
	}

	public void ShotRaycast(Vector3 direction, float length)
	{
		RaycastHit2D[] array = Physics2D.RaycastAll(bulletFire.transform.position, direction, length, Ground.shootableLayerMask);
		LineRenderer lineRenderer = null;
		if (!bulletFire.laser && !bulletFire.ps && (bool)bulletLine)
		{
			lineRenderer = UnityEngine.Object.Instantiate(bulletLine);
			lineRenderer.SetPosition(0, bulletFire.transform.position + direction * length * UnityEngine.Random.Range(0f, 0.2f));
			lineRenderer.SetPosition(1, bulletFire.transform.position + direction * length);
			lineRenderer.endWidth = 0.02f + damage / 600f;
			lineRenderer.startWidth = lineRenderer.endWidth;
			UnityEngine.Object.Destroy(lineRenderer.gameObject, 0.02f);
		}
		if (array.Length == 0)
		{
			return;
		}
		float num = penetration;
		RaycastHit2D[] array2 = array;
		for (int i = 0; i < array2.Length; i++)
		{
			RaycastHit2D raycastHit2D = array2[i];
			if (!(raycastHit2D.collider != null) || !(raycastHit2D.collider.tag == "Body"))
			{
				continue;
			}
			BodyPart component = raycastHit2D.collider.GetComponent<BodyPart>();
			if (!component)
			{
				continue;
			}
			component.OnHit(this, direction, raycastHit2D.point);
			num -= component.resistance;
			if (num <= 0f)
			{
				if ((bool)lineRenderer)
				{
					lineRenderer.SetPosition(1, raycastHit2D.point);
				}
				break;
			}
		}
	}

	public void Fire()
	{
		if (fireSince > Time.time)
		{
			return;
		}
		if ((bool)player)
		{
			if (ammo == 0 && onFire)
			{
				Stop();
				return;
			}
			if (!cocked || !player.controllable || !onFire || lastFireAt + 60f / rpm > Time.time)
			{
				return;
			}
		}
		else if (lastFireAt + 60f / rpm > Time.time)
		{
			return;
		}
		if (chargeConfigs.Length != 0)
		{
			for (int i = 0; i < chargeConfigs.Length; i++)
			{
				if (!chargeConfigs[i].hasApplied && Time.time - fireSince >= chargeConfigs[i].duration)
				{
					damage = chargeConfigs[i].damage;
					penetration = chargeConfigs[i].penetration;
					stoppingPower = chargeConfigs[i].stoppingPower;
					recoil = chargeConfigs[i].recoil;
					_chargeShakePower = chargeConfigs[i].shakePower;
					fireAudio = chargeConfigs[i].fireAudio;
					chargeConfigs[i].callback?.Invoke();
					chargeConfigs[i].hasApplied = true;
				}
			}
			if (Time.time - fireSince >= chargeConfigs[chargeConfigs.Length - 1].duration)
			{
				Stop();
				return;
			}
		}
		else
		{
			SendDamage();
		}
		if ((bool)fireLoopAudio)
		{
			if (audioSource.clip != fireLoopAudio)
			{
				audioSource.loop = true;
				audioSource.clip = fireLoopAudio;
				audioSource.Play();
			}
		}
		else if ((bool)lastAmmoAudio && ammo == 1)
		{
			audioSource.PlayOneShot(lastAmmoAudio);
			Invoke("BulletClipOut", 0.15f);
		}
		else if ((bool)fireAudio)
		{
			audioSource.PlayOneShot(fireAudio);
		}
		if ((bool)launcherSmoke)
		{
			launcherSmoke.Play();
		}
		lastFireAt = Time.time;
		if (!player || !player.campaignGame.isPlayground || !DO.Playground.unlimitedAmmo || !player.weapon)
		{
			ammo--;
		}
		BulletFire bulletFire = null;
		if ((bool)this.bulletFire.laser)
		{
			bulletFire = this.bulletFire;
		}
		else if ((bool)this.bulletFire.ps)
		{
			bulletFire = this.bulletFire;
			this.bulletFire.StartPs();
		}
		else
		{
			bulletFire = UnityEngine.Object.Instantiate(this.bulletFire, this.bulletFire.transform.position, this.bulletFire.transform.rotation);
		}
		bulletFire.gameObject.SetActive(value: true);
		if ((bool)player)
		{
			player.changingWeapon = false;
			if (recoil != 0f)
			{
				base.transform.Rotate(0f, 0f, UnityEngine.Random.Range((0f - recoil) / 5f, recoil) / DO.Campaign.playerStrength);
				base.transform.position = new Vector2(base.transform.position.x - Mathf.Min(0.05f, recoil / 60f), base.transform.position.y);
			}
			if (shakePower > 0f)
			{
				shake.Strength = shakePower;
				Shaker.ShakeAll(shake);
			}
			if (!automatic)
			{
				Stop();
			}
			if (!autoCocking && ammo > 0)
			{
				cocked = false;
				animator.enabled = true;
				animator.Play("Cock" + base.gameObject.name.Replace("(Clone)", ""));
			}
			else if (ammo > 0)
			{
				cocked = true;
			}
			if (autoCocking && !isBulletStay)
			{
				BulletOut();
			}
		}
		else
		{
			cocked = true;
			BulletOut();
		}
	}

	public void SendDamage()
	{
		if (burstCount == 0 && projectileObject == null)
		{
			ShotRaycast(bulletFire.transform.TransformDirection(Vector3.right), 13f);
		}
		else if (projectileObject != null)
		{
			GameObject obj = UnityEngine.Object.Instantiate(projectileObject, projectileObject.transform.position, base.transform.rotation);
			obj.SetActive(value: true);
			obj.GetComponent<Rigidbody2D>().velocity = base.transform.right * projectileForce;
			if (bulletFire.ps == null)
			{
				magazine.gameObject.SetActive(value: false);
			}
		}
		else
		{
			for (int i = 0; i < burstCount; i++)
			{
				ShotRaycast(bulletFire.transform.TransformDirection(new Vector2(20f, -(burstCount / 2) + i)).normalized, 13f);
			}
		}
	}

	public void BulletOut()
	{
		if ((!(CampaignGame.framerate < 20f) || capacity <= 50) && !bulletFire.laser && !bulletFire.ps && chargeConfigs.Length == 0)
		{
			int num = 1;
			if (isBulletStay)
			{
				num = capacity;
			}
			for (int i = 0; i < num; i++)
			{
				BulletShell obj = UnityEngine.Object.Instantiate(bulletShell, bulletShell.transform.position, Quaternion.identity);
				obj.transform.rotation = bulletShell.transform.rotation;
				obj.gameObject.SetActive(value: true);
			}
		}
	}

	public void BulletClipOut()
	{
		if ((bool)bulletClip)
		{
			BulletShell obj = UnityEngine.Object.Instantiate(bulletClip, bulletClip.transform.position, Quaternion.identity);
			obj.transform.rotation = bulletClip.transform.rotation;
			obj.gameObject.SetActive(value: true);
		}
	}

	public void OpenFire()
	{
		onFire = true;
		if ((bool)warmupAudio && !onReload)
		{
			audioSource.loop = false;
			audioSource.clip = warmupAudio;
			audioSource.Play();
			fireSince = Time.time + warmupAudio.length;
		}
		else if (!warmupAudio && (bool)fireLoopAudio && !onReload)
		{
			fireSince = Time.time;
		}
	}

	public void Stop()
	{
		if (!onFire)
		{
			return;
		}
		audioSource.loop = false;
		onFire = false;
		if ((bool)fireLoopAudio)
		{
			audioSource.Stop();
		}
		if (chargeConfigs.Length != 0 && !onReload && chargeConfigs[0].hasApplied && chargeConfigs[0].damage > 0f)
		{
			audioSource.PlayOneShot(fireAudio);
			SendDamage();
			shake.Strength = _chargeShakePower;
			Shaker.ShakeAll(shake);
			for (int i = 0; i < chargeConfigs.Length; i++)
			{
				chargeConfigs[i].hasApplied = false;
			}
			lastFireAt = Time.time;
		}
		if ((bool)sleepAudio && !onReload)
		{
			audioSource.loop = false;
			audioSource.clip = sleepAudio;
			audioSource.Play();
		}
		else
		{
			audioSource.clip = null;
		}
		if ((bool)bulletFire.laser)
		{
			bulletFire.gameObject.SetActive(value: false);
		}
		else if ((bool)bulletFire.ps)
		{
			bulletFire.StopPs();
		}
		OnStopFire?.Invoke();
	}

	public void Reload()
	{
		if (!player || onReload || player.isPlacingItem)
		{
			return;
		}
		newMagazineChanged = false;
		Stop();
		onReload = true;
		foreach (Transform item in magazinePos.transform)
		{
			if (item.gameObject.name != magazine.name)
			{
				UnityEngine.Object.Destroy(item.gameObject);
			}
		}
		if (!isBulletStay)
		{
			dropMagazine = UnityEngine.Object.Instantiate(magazine, magazinePos.transform);
		}
		magazine.transform.SetParent(player.body.magazineHolder.transform);
		magazine.sr.color = new Color(0f, 0f, 0f, 0f);
		magazine.transform.localPosition = Vector2.zero;
		PlayAnimation("Magazine" + base.gameObject.name.Replace("(Clone)", ""));
		cocked = false;
		newMagazinePickedUp = false;
		newMagazineReady = false;
		if (projectileObject != null)
		{
			magazine.gameObject.SetActive(value: true);
		}
		lastRealodAt = Time.time;
	}

	public void PlayAnimation(string name)
	{
		animator.enabled = true;
		animator.Play(name);
	}

	public void TakeMagazion(GameObject hand)
	{
		if (((bool)GetComponent<Bow>() || !newMagazineChanged) && (bool)magazine)
		{
			hand.transform.position = magazine.transform.position;
			newMagazinePickedUp = true;
			magazine.sr.color = new Color(1f, 1f, 1f, 1f);
			magazine.transform.SetParent(hand.transform);
			magazine.transform.localRotation = Quaternion.Euler(0f, 0f, 0f);
		}
	}

	public void MagazineReleased()
	{
		if ((bool)dropMagazine)
		{
			dropMagazine.rb.isKinematic = false;
			dropMagazine.transform.localRotation = Quaternion.Euler(0f, 0f, UnityEngine.Random.Range(5, 15));
			dropMagazine.transform.localScale = new Vector3(1f, 1f, 1f);
			UnityEngine.Object.Destroy(dropMagazine.gameObject, 15f);
		}
	}

	public void MagazineChanged()
	{
		newMagazineChanged = true;
		magazine.transform.SetParent(magazinePos.transform);
		magazine.transform.localPosition = Vector2.zero;
		magazine.transform.localRotation = Quaternion.Euler(0f, 0f, 0f);
		magazine.transform.localScale = new Vector3(1f, 1f, 1f);
		magazine.sr.color = new Color(1f, 1f, 1f, 1f);
		ammo = capacity;
	}

	public void Cocked()
	{
		cocked = true;
		onReload = false;
		if (onFire)
		{
			OpenFire();
		}
	}

	public void StopAnimator()
	{
		animator.enabled = false;
	}

	public void PlayAudio(AudioClip audioClip)
	{
		audioSource.clip = audioClip;
		audioSource.Play();
	}
}
